#include "LJNAudioPlayer.h"
#include <iostream>
#include "fmod.hpp"
#include "fmod_errors.h"

namespace LJNAudio {

class AudioPlayer::AudioPlayerImpl {
public:
    AudioPlayerImpl() : system(nullptr), sound(nullptr), channel(nullptr), pitchShiftDSP(nullptr) {
        FMOD::System_Create(&system); // 创建FMOD系统对象
        system->init(1, FMOD_INIT_NORMAL, nullptr); // 初始化FMOD系统
    }
    ~AudioPlayerImpl() {
        Destroy();
        system->release(); // 释放FMOD系统对象
    }
    bool Init(const std::string& file_path) {
        FMOD_RESULT result = system->createSound(file_path.c_str(), FMOD_DEFAULT, nullptr, &sound); // 创建声音对象
        return result == FMOD_OK;
    }
    void Reset() {
        Stop();
        SeekTo(0);
    }
    void Destroy() {
        if (sound) {
            sound->release(); // 释放声音对象
            sound = nullptr;
        }
    }

    int32_t GetDurationInMs() {
        if (sound) {
            unsigned int duration;
            sound->getLength(&duration, FMOD_TIMEUNIT_MS);
            return duration;
        }
        return -1;
    }

    bool Play() {
        FMOD_RESULT result = system->playSound(sound, nullptr, false, &channel); // 播放声音
        if (pitchShiftDSP) {
            channel->addDSP(0, pitchShiftDSP);
        }
        
        return result == FMOD_OK;
    }
    bool Pause() {
        bool isPaused;
        channel->getPaused(&isPaused);
        FMOD_RESULT result = channel->setPaused(!isPaused); // 切换暂停状态
        return result == FMOD_OK;
    }
    bool Stop() {
        FMOD_RESULT result = channel->stop(); // 停止播放
        return result == FMOD_OK;
    }

    bool SeekForward(uint32_t millisecond) {
        unsigned int position;
        channel->getPosition(&position, FMOD_TIMEUNIT_MS);
        position += millisecond;
        FMOD_RESULT result = channel->setPosition(position, FMOD_TIMEUNIT_MS); // 向前跳转
        return result == FMOD_OK;
    }
    bool SeekBackward(uint32_t millisecond) {
        unsigned int position;
        channel->getPosition(&position, FMOD_TIMEUNIT_MS);
        if (millisecond > position) position = 0;
        else position -= millisecond;
        FMOD_RESULT result = channel->setPosition(position, FMOD_TIMEUNIT_MS); // 向后跳转
        return result == FMOD_OK;
    }
    bool SeekTo(uint32_t millisecond) {
        FMOD_RESULT result = channel->setPosition(millisecond, FMOD_TIMEUNIT_MS); // 跳转到指定位置
        return result == FMOD_OK;
    }

    bool SetSpeed(float speed) {
        return false;
    }
    bool SetPitch(float pitch) {
        if (fabs(pitch) > 1e-4) {
            if (!pitchShiftDSP) {
                system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &pitchShiftDSP);
                pitchShiftDSP->setParameterInt(FMOD_DSP_PITCHSHIFT_FFTSIZE, 2048);
                pitchShiftDSP->setParameterInt(FMOD_DSP_PITCHSHIFT_OVERLAP, 8);
                pitchShiftDSP->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, pitch);
                if (channel) {
                    FMOD_RESULT result = channel->addDSP(0, pitchShiftDSP);
                    if (result != FMOD_OK) {
                        std::cout << "Failed to add DSP to channel:" << result << std::endl;
                    }
                }
            }
            pitchShiftDSP->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, pitch);
            return true;
        } else {
            if (pitchShiftDSP) {
                if (channel) {
                    channel->removeDSP(pitchShiftDSP);
                }
                pitchShiftDSP->release();
                pitchShiftDSP = nullptr;
            }
            return true;
        }
    }
    FMOD::System* system;
    FMOD::Sound* sound;
    FMOD::Channel* channel;
    FMOD::DSP* pitchShiftDSP;
};


AudioPlayer::AudioPlayer() 
    : m_impl(new AudioPlayerImpl()) {
}

AudioPlayer::~AudioPlayer() {
}

bool AudioPlayer::Init(const std::string& file_path) {
    return m_impl->Init(file_path);
}

void AudioPlayer::Reset() {
    m_impl->Reset();
}

void AudioPlayer::Destroy() {
    m_impl->Destroy();
}

bool AudioPlayer::Play() {
    return m_impl->Play();
}

bool AudioPlayer::Pause() {
    return m_impl->Pause();
}

bool AudioPlayer::Stop() {
    return m_impl->Stop();
}

int32_t AudioPlayer::GetDurationInMs() {
    return m_impl->GetDurationInMs();
}

bool AudioPlayer::SeekForward(uint32_t millisecond) {
    return m_impl->SeekForward(millisecond);
}

bool AudioPlayer::SeekBackward(uint32_t millisecond) {
    return m_impl->SeekBackward(millisecond);
}

bool AudioPlayer::SeekTo(uint32_t millisecond) {
    return m_impl->SeekTo(millisecond);
}

bool AudioPlayer::SetSpeed(float speed) {
    return m_impl->SetSpeed(speed);
}

bool AudioPlayer::SetPitch(float pitch) {
    return m_impl->SetPitch(pitch);
}

} // namespace LJNAudio
